﻿// ------------------------------------------------------------------------------------------------
// <copyright file="SolutionsComparer.cs" company="Hiyoko">
//   Copyright (c) 2015 All Rights Reserved
// </copyright>
// <summary>
//   This file contains the core logic of this plugin.
// </summary>
// ---------------------------------------------------------------------------------------------

using Hiyoko.SolutionsComparer.Helper;
using Hiyoko.SolutionsComparer.Manager;
using McTools.Xrm.Connection;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using XrmToolBox;
using XrmToolBox.Attributes;

// If empty strings are left, default values are used
[assembly: BackgroundColor("")]
[assembly: PrimaryFontColor("")]
[assembly: SecondaryFontColor("")]
[assembly: SmallImageBase64("iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAAOPSURBVFhH7ZZdSJNhFMfdnPvSqdPNbU43WcrUwcAtN8vRoBKiO6PdBV0G3dRNN0VZRBdRdm8fl4lIFAZeFPRBEIRIXkQkQV7kXVFS2YeZW79H9ozXfby9OqUuGhzevc9znnP+55z/Oc9bUVdXd8Jqtc4ibzZZZm022/mhoSF9hdrPYDAss5/ZCtHpdOnu7u52VQBb4Vhps6enJ/wfwL+dAaPR+G6reFBZWfk1Eol4VDPg8XgSFotlBCDXNlPMZvNIc3Pz3j+l/+/vOxyO/aTqJkhGtQqz43pLS4t3U9CT9o/r4QDO510uV0zhXCfAOJ3OVE1NzWXkBnKJ9wM+n0+9/lkjmqegXq9fdrvdSek8mUwaGOXnWF9gLZ0XSJrMLtTX158UemrZ0gogjbEz0hDkdUDe+xqyl+aOuev3++tLgdAEgNTPBYNBmzRSXV19S+mcaBdxdNtkMl3hOY7+F+U+a6OpVKqyGAhNAER95eGmpqZBcdFkHaRpuYm2tja/0nhHR4cXpwLkqh76Pzm3pwBAVVXVkoY0ZhobG3eLw6KeOHwuzxDxU0hoKRZZNBqtQveh1KVk9wr0GhoajpG+aWSmlJDOGYw5xGFI6Id0i9Io5wfVCMb+ANH/Evri6k8kEvYCfRGVQKsm8hBzI4rB1W8IAGfi8bhLDYBoUfQ/S8ChUKh3jT4ROUVteO4rJa2trQPyy4ZS9CoiyhCRUw0AgD3of5IAurq64mv0IcoUCiuCVKUEnqzEYrFacZABsw29b4oSDKgBQL9fAhZ+yPZqKXM/FjV1AVOtP0tCM8SblQAg2SSfXcZSJCTAO1KX/8+K6WkCUFtbe0oepgxHpVERFR+fI319fWs6AT5ZWb+KnmzDNNk4uGEA3BkvZLsJstJSTyQI8aRMr4lw2Ov1HmdmDPP+SrlP1qbb29tNGwYg+EEEh6UBLqQ2nMwpnaj9F/cC4ztSAICezr9ESpaEPv5AR4Skkc7OTg9Rj2HjezHnrK/kZWkeLgXyu+CR1iiyqX4J6dzSiJjvjOEgt+IFyjLJc4p0T1D/s4FAYDug3+aVYkrwIwciHA5X2+32HRzYqVUw7FNrPeUes2UX6c/NAQEGP2PcjmatNsrV04mPFdEtykwA4iLvunKNaz5PG59GOQcCfizRzoc0GyhXUQwr2nNcmQX48aNcu+s6L8gHQR9LECIL6zKwGcridqRbHtC+7yH/kd81RjLEXhuLNwAAAABJRU5ErkJggg==")]
[assembly: BigImageBase64("iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuM4zml1AAAAqDSURBVHhe7ZwLbJZXGcf7QVva0pbeoBcoLfQCbaEtlDttSQnQcicbDKRUFCLMa+bmYohLELMlkohhzJkty2a2qZvTxGVblsVMozG6ZDLdJngNKOisG4zhlHJv/f1Ja5rac97zfn2/r7S8X/Kmgfd87znP/zyX//Oc5/0SEvisWLGiaMqUKbsqKyu/VVZW9v3RdFVUVDxdXFx89/z582t6enoikjfQT319fUVmZuaJMWPGXOfBPaPxikQiPSkpKZ1z585dFyh4elhRUdF3NcFoBG6gTBMmTDi9bdu2okBBzM7OvnYrgCcZpSgzZsy4PVAAMd1bQvv6lASXdU+gAN4q2tcPwC+EAA4h2KGBIYBDsZoQwCFon4APAQwBHF6yHmpgqIGhBo5o4h2a8M1mwqmpqSNao/xywlmzZt0ZaCYyceLEY34XMVLHjxs37vKyZcvmBQog1YntiYmJl0cqKK7rHjt27LXp06c/tH///jGBAsiOJNbU1HRQVH2TouM/kpOTO0fThdZ14qb+QJX9wJYtW9IDBa/fwyKrVq3KoWLLPGXlo+lCOcoWL148CfDGxgq88LkhAiECIxuBJUuWFFVXV38CZ3sASYbl4rziQEFBQQfrSB5RaHImrGPNXyvMD9fpHOcy3fn5+T+dM2dOFeAFf3Ybyx2ZPHny48MFnDgcG3e1sLDwKehUXjRy7tmzJ6m9vb1wzZo1Jbq2bt1azP9NiNtGcKx5yZWMBj0O8C6zgV9buXLleEfwIg0NDWl0GVRWVVXtgm79ID09/WhGRsY7/D07fvz4s1jTe/z9PZ0WP6cr4eCCBQtacAs5EOhExzn8DRuuY02ZLUI+iv/NcFnxpk2bcgFkb1ZW1stpaWlnAb/ba0NlWUlJSRcB+BgNBEeYK9g0rnfhw1JMyMvL+xFmm+UFHmPSAe4jOTk5xwA96iYAwOwmK7kwderUJ/C15UGmdHEHEC16F22Y4QXe+vXr8zHx58jVu7y0zfU+QF7HxE9QldkRlJ+MK4CY1H/oArvDC7za2tpGgH47VgGOfP/StGnTDrq6ENt64wagwMAXKeKmmBYk0wLgNvzcu65aFe04XIIYwLMuruSmAFBRsrGxsdq2GAoaLYB3OlpQ/H5PwWzSpEmPl5eXj/OyCtP9uGig+g/xZ/ezCGM9TvSEiPkXVxD6oiwZ1HuU4k7y79/oL+b5Pn7zqutzxEVnzpy5T6W9aECMC4ASCk5WZ9xFukehNU8rWroIDu/7gM7TIwSDtXDDmTx7CpE6c9GiRZMpEs+GJ27FXbzMvE6Rmwh9Dr+7/KYFEO17vq2tzWQmEUz3DgLMFS/wEPTfAP1Ic3NzhVcUpQaYDGVphjK9qlTV69kcb/xk3bp1aX5BjLkGogVXbbu7cOHCfDKIt7wEROtOUiBtReOS/AipSEvE3ScGYJtDPHP27Nl7vDZm4NwxB5Dg8VeCx0ST0L3nMtaUEt94CuAa/QrXN6cif0lJyV2iLzYQaQM+ihvIcd4gHLCTz/HSDtt98u3nTVqjYgBU4he276M558lG1kQLXh8YokiY/yGRadN8AHwR/9nsDCB2/6ehgOPyXebYZxIe51+NXzOaliItmvOo/JmzUJaBCjZo80nTujUfwelB57kwn13scEwrMpjEdov5ftamEdASpX1lzgI5DISy3GUrRrDhZ2QZDo9KSBD3wcF/Etv/I05UVY5zQV64iHNEwpLBFiOtUi3QpsVE0B8GpX19ayAQFeOXjXwT+a9v3LhxiROAvYNUZ8vDz1RBZuuDvAgetSaCqtoe5vSKDUC05Yt+BHEZq4CCwrxkM2MO4W9zedawjmGjcqEvx02CoAk9KioEvUidEeNXH7KRduZ9IOh5A3+e+B8R+m8mAAG3e/Xq1ZWBT8wDCVy7+GOMxlSx3QNJLBbo8kw0sAAAO00AYmbXqETHBEBcR4cNQNzZN1xkuDFGKo2vySXa1ZMiLQ7yomWkztRWoZYLADRSCrXezZs3b5azII4DxQdJLXV8a+TAZCSHnB4nggvaXyIqHYdEnoc2dAV5kdD/fffu3YMye0pImZSurCSaCP5xJ0F8DJLMFB6+ZwterM2tj1ADcdaeSbxtMts9NKybqFcwmHzww1Q41wu27+fm5n49yPMLrUNpJe7B2BepGuHy5ctbnPaEA+0T0YLj8j1FUhbcMNhiBAzdCAdtpoSv+l1dXV2WkzCOg1TYwNqMPZHc6+ro6Mh1elw8WnwBYK9pMZjo7bZSE4XRK9T82vl+IB0L4oC4FSv3JF9+zQm83kExr8bgsB8zBRLqb3mUqU7ZtJn7J1St9iOUaSz+/qNsijF1VUmLDfPld2MOIP7mNczG2H0AqT1sI7XKlTm3eGaIJ2gRtG8Rm2E9MlCXrpoy/WxWzAGEtL6v32YwLQrK0MCYszYtlGNX3izu6Ec4jZWvpeLdpJqil9+mEmO0FtO8MQdQ7SP4wXtNC9i5c2cKHQPPegmnY0jox1H4oxJ9J5+oQgQc99P4+k6vM2ao3IctLS2+tE8yxRxAzQGdeVN92CYQW1tbS9EQp+NMwPiAQHAYzW2mvpc5sFihDVGaCEXbAst4RYHIS05tDq7ky4zz3cUfFwCJtF0SyGZ+1CbbXds45DMR+gLdC+/AFV9Ewx8DzIc5lH+CEtjrgHyG+86vb8BH31i7dm22X/cQNw2U+bDIH2/evDnVtEhRjNLS0m+qHuelMUHfx0J+hZ8svGkBlMBoVzdVju22XxBSpMXsvhNvEHuD1DPRvEsSFxPu0xjV/3QuYdtpMpds9dDE+9eUROgJZl/126EQVwAFijoKLIfsN7DlfibCPAC9OR+0udqep7NjNdw7/87WcHSoaqcJKJ/yKhIoexF/wz+9EcuCx0BAyYUvEOE3OFEleNXFeO5w31xqCIIUt7o4baV7nFHsZa1v40c9WzQGyqMARtnsX/C8C66ykrGoGaDWc334mkdcG3pcJ3cdh0CnSZtcSXFEfSuA3qYfTFP9krTrvN40lVtQEOi7kOcKpn+JTTpFGvkzdV5xylasDeM751zXJ+5KQbfYCiKEsxTe9JYXS3ed1Oe4buWmTU1NriDekEWmrWo2HQQ1pHdLAeZO5LgPYb9CgLoX37mCq0HHqTt27PhfDi6/pkZ1vR3gsk7l4FRmXvTy1wkbNmzIoALxOQjpg2QDR+J98brCPdF0RXma1yADlNoB7sMu3VoCWdYJNz3kCWI0ixmp31GEp5D7nKvrIjJfJjLfHb4y22/H9X4gmdHrLqasMfjUi/jSbU6ReaRqlt9163dV8cF/dgWRSP5PfO2gxxN+5x4t4yMEnSaA+dAVRDKp33plUqMFHGc5qAJ9DDrkxIfFVvCfL/GCY6bzBKN9oHJfymD3q1vfRRMVfOCiT9redxntmP2ffHonD836NjecOnZF4Akqn7nlgLIJTK0yh8j8S9ekgixHle7w0x8BvXPidXI3wMxDAAcisHTp0kYi8xkXfxiiZ0AA/3abw3sl8pfhZzAElLZReLgPEI3nMxSGXw3RsyDQ+3LOYf1sQH9zVhGa08CjEOppIYAeCOiMmUJCG2WzF6jKdKF1x6mmf54S3I0TvP8CIOeU5SkMg2AAAAAASUVORK5CYII=")]

namespace Hiyoko.SolutionsComparer
{
    public partial class SolutionsComparer : UserControl, IMsCrmToolsPluginUserControl, ICodePlexPlugin
    {
        #region Private members

        /// <summary>
        /// Microsoft Dynamics CRM 2011 Organization Service (source)
        /// </summary>
        private IOrganizationService _sourceService;

        /// <summary>
        /// Microsoft Dynamics CRM 2011 Organization Service (target)
        /// </summary>
        private IOrganizationService _targetService;

        /// <summary>
        /// Panel used to display progress information
        /// </summary>
        private Panel _infoPanel;

        /// <summary>
        /// The file manager used to access and manipulate temporary data
        /// </summary>
        private FileManager _fileManager;

        #endregion Private members

        #region Properties

        /// <summary>
        /// Gets the organization service used by the tool (source)
        /// </summary>
        public IOrganizationService Service
        {
            get { return _sourceService; }
        }

        /// <summary>
        /// Gets the organization service used by the tool (target)
        /// </summary>
        public IOrganizationService TargetService
        {
            get { return _targetService; }
        }

        /// <summary>
        /// Gets the logo to display in the tools list
        /// </summary>
        public Image PluginLogo
        {
            get { return toolImageList.Images[0]; }
        }

        /// <summary>
        /// Gets the CodePlew project Url
        /// </summary>
        public string CodePlexUrlName
        {
            get { return "https://xrmsolutionscomparer.codeplex.com/"; }
        }

        #endregion Properties

        #region Constructor

        /// <summary>
        /// Initializes a new instance of class <see cref="SolutionsComparer"/>
        /// </summary>
        public SolutionsComparer()
        {
            InitializeComponent();
        }

        #endregion Constructor

        #region Event handlers

        /// <summary>
        /// EventHandler to request a connection to an organization
        /// </summary>
        public event EventHandler OnRequestConnection;

        /// <summary>
        /// EventHandler to close the current tool
        /// </summary>
        public event EventHandler OnCloseTool;

        #endregion Event handlers

        #region Public methods

        /// <summary>
        /// Updates the organization service used by the tool
        /// </summary>
        /// <param name="newService">Organization service</param>
        /// <param name="detail">Details of the connection</param>
        /// <param name="actionName">Action that requested a service update</param>
        /// <param name="parameter">Parameter passed when requesting a service update</param>
        public void UpdateConnection(IOrganizationService newService, ConnectionDetail detail, string actionName = "", object parameter = null)
        {
            ListView currentListView;

            ((OrganizationServiceProxy)((OrganizationService)newService).InnerService).Timeout = new TimeSpan(0, 1, 0, 0);
            var serviceAddress = ((OrganizationServiceProxy)((OrganizationService)newService).InnerService).ServiceConfiguration.CurrentServiceEndpoint.Address.Uri.ToString();

            if (actionName == "TargetOrganization")
            {
                lblTargetStatus.Text = serviceAddress;
                lblTargetStatus.ForeColor = Color.Green;

                lblSelectedTargetSolution.Text = @"Unselected";
                lblSelectedTargetSolution.ForeColor = Color.Red;

                _targetService = newService;
                currentListView = lstTargetSolutions;
            }
            else
            {
                lblSourceStatus.Text = serviceAddress;
                lblSourceStatus.ForeColor = Color.Green;

                lblSelectedSourceSolution.Text = @"Unselected";
                lblSelectedSourceSolution.ForeColor = Color.Red;

                _sourceService = newService;
                currentListView = lstSourceSolutions;
            }

            currentListView.Items.Clear();
            tsbCompareSolutions.Enabled = false;
            tsbSaveOutput.Enabled = false;
            tsbSaveDiffOutput.Enabled = false;

            if (_fileManager != null)
            {
                FileManager.DeleteTempFiles();
            }
            _fileManager = new FileManager();

            var retrievedSolutions = CrmSolutionHelper.RetrieveSolutions(newService);
            foreach (var solution in retrievedSolutions)
            {
                var item = new ListViewItem
                {
                    Tag = solution.SolutionId,
                    Text = solution.UniqueName
                };

                item.SubItems.Add(solution.FriendlyName);
                item.SubItems.Add(solution.Version);
                item.SubItems.Add(solution.InstalledOn.ToShortDateString());
                item.SubItems.Add(solution.Publisher);
                item.SubItems.Add(solution.Description);
                currentListView.Items.Add(item);
            }
        }

        /// <summary>
        /// Stuff to do when the plugin is closed
        /// </summary>
        /// <param name="info"></param>
        public void ClosingPlugin(PluginCloseInfo info)
        {
            // Delete temporary files.
            FileManager.DeleteTempFiles();
        }

        #endregion Public methods

        #region Private methods

        /// <summary>
        /// When the user clicks on connect to organization.
        /// </summary>
        private void BtnConnectOrganization(object sender, EventArgs e)
        {
            var button = (Button)sender;
            if (button == null)
            {
                throw new ApplicationException("An error occured: object sender should not be null at this point.");
            }

            if (OnRequestConnection == null)
                return;

            var args = new RequestConnectionEventArgs
            {
                ActionName = "SourceOrganization",
                Control = this
            };

            if (button.Name.Equals("btnSelectTarget"))
            {
                args = new RequestConnectionEventArgs
                {
                    ActionName = "TargetOrganization",
                    Control = this
                };
            }
            OnRequestConnection(this, args);
        }

        /// <summary>
        /// When the user clicks compare.
        /// </summary>
        private void BtnCompareClick(object sender, EventArgs e)
        {
            // Check that both source and target solutions are selected.
            if (lstSourceSolutions == null
                || lstSourceSolutions.SelectedItems.Count == 0
                || _sourceService == null)
            {
                MessageBox.Show(
                    @"Please select a solution from the source organization.",
                    @"Warning",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                return;
            }

            if (lstTargetSolutions == null
                || lstTargetSolutions.SelectedItems.Count == 0
                || _targetService == null)
            {
                MessageBox.Show(
                    @"Please select a solution from the target organization.",
                    @"Warning",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                return;
            }

            var sourceSolution = lstSourceSolutions.SelectedItems[0].Text;
            var changedSolution = lstTargetSolutions.SelectedItems[0].Text;

            // Instanciate the WorkerParameters class.
            var workerParameters = new[] { sourceSolution, changedSolution };

            // Begin comparison.
            _infoPanel = InformationPanel.GetInformationPanel(this, "Comparing solutions...", 340, 100);

            var worker = new BackgroundWorker();
            worker.DoWork += WorkerDoWork;
            worker.ProgressChanged += WorkerProgressChanged;
            worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
            worker.WorkerReportsProgress = true;
            worker.RunWorkerAsync(workerParameters);
        }

        /// <summary>
        /// The comparison job.
        /// </summary>
        private void WorkerDoWork(object sender, DoWorkEventArgs e)
        {
            var bw = (BackgroundWorker)sender;
            var parameters = (string[])e.Argument;

            if (bw == null)
            {
                throw new ApplicationException("An error occured: object sender should not be null at this point.");
            }

            if (parameters == null
                || parameters.Length != 2
                || string.IsNullOrEmpty(parameters[0])
                || string.IsNullOrEmpty(parameters[1]))
            {
                throw new ApplicationException("An error occured: worker parameters should not be null or empty at this point.");
            }

            // Export source and target solutions.
            bw.ReportProgress(0, "Exporting source solution...");
            CrmSolutionHelper.ExportSolution(_sourceService, parameters[0], _fileManager.SourceZipFilePath);

            bw.ReportProgress(25, "Exporting target solution...");
            CrmSolutionHelper.ExportSolution(_targetService, parameters[1], _fileManager.ChangedZipFilePath);

            // Extract source and target solutions content.
            bw.ReportProgress(50, "Unzipping source solution...");
            ZipHelper.UnzipToFile(_fileManager.SourceZipFilePath, _fileManager.SourceDirectory);

            bw.ReportProgress(60, "Unzipping target solution...");
            ZipHelper.UnzipToFile(_fileManager.ChangedZipFilePath, _fileManager.ChangedDirectory);

            // Compare customizations.xml files.
            bw.ReportProgress(70, "Comparing customizations...");
            XmlDiffPatchHelper.Compare(
                   _fileManager.SourceCustomizationsFilePath,
                   _fileManager.ChangedCustomizationsFilePath,
                   _fileManager.DiffGramFilePath);

            // Generate HTML output.
            bw.ReportProgress(80, "Generating HTML output...");
            XmlDiffPatchHelper.FormatResult(
                _fileManager.SourceCustomizationsFilePath,
                _fileManager.DiffGramFilePath,
                _fileManager.HtmlResultPath);

            // Generate diff onyly HTML output.
            bw.ReportProgress(90, "Generating diff. only HTML output...");
            XmlDiffPatchHelper.FormatDiffResult(
                _fileManager.HtmlResultPath, _fileManager.HtmlDiffResultPath);

            tsbSaveOutput.Enabled = true;
            tsbSaveDiffOutput.Enabled = true;

            // Display HTML output
            bw.ReportProgress(100, "Displaying HTML output...");
            var proc = new Process
            {
                StartInfo =
                {
                    UseShellExecute = true,
                    FileName = _fileManager.HtmlResultPath
                }
            };
            proc.Start();
        }

        /// <summary>
        /// When the progress of the job change.
        /// </summary>
        private void WorkerProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            InformationPanel.ChangeInformationPanelMessage(_infoPanel, e.UserState.ToString());
        }

        /// <summary>
        /// When the job is completed.
        /// </summary>
        private void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _infoPanel.Dispose();
            Controls.Remove(_infoPanel);
        }

        /// <summary>
        /// Save HTML output file to disk.
        /// </summary>
        private void tsbSaveOutput_Click(object sender, EventArgs e)
        {
            var tsbSaveButton = (ToolStripButton)sender;
            if (tsbSaveButton == null)
            {
                throw new ApplicationException("An error occured: object sender should not be null at this point.");
            }

            var sourceFilePath = _fileManager.HtmlResultPath;
            if (tsbSaveButton.Name.Equals("tsbSaveDiffOutput"))
            {
                sourceFilePath = _fileManager.HtmlDiffResultPath;
            }

            var saveFileDialog = new SaveFileDialog
            {
                Filter = @"HTML files (*.html)|*.html|All files (*.*)|*.*",
                FilterIndex = 1,
                RestoreDirectory = true
            };

            if (saveFileDialog.ShowDialog() != DialogResult.OK)
                return;

            var content = File.ReadAllBytes(sourceFilePath);
            using (var fileStream = saveFileDialog.OpenFile())
            {
                fileStream.Write(content, 0, content.Length);
            }

            MessageBox.Show(
                @"HTML result file has been saved at the specified path.",
                @"Information",
                MessageBoxButtons.OK,
                MessageBoxIcon.Information);
        }

        /// <summary>
        /// When the user selects an item, display confirmation.
        /// </summary>
        private void lstSolutions_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            var listView = (ListView)sender;
            if (listView == null)
            {
                throw new ApplicationException("An error occured: object sender should not be null at this point.");
            }

            if (listView.SelectedItems.Count == 0)
            {
                if (listView.Name.Equals("lstSourceSolutions"))
                {
                    lblSelectedSourceSolution.Text = @"Unselected";
                    lblSelectedSourceSolution.ForeColor = Color.Red;
                }
                else if (listView.Name.Equals("lstTargetSolutions"))
                {
                    lblSelectedTargetSolution.Text = @"Unselected";
                    lblSelectedTargetSolution.ForeColor = Color.Red;
                }
            }
            else
            {
                if (listView.Name.Equals("lstSourceSolutions"))
                {
                    lblSelectedSourceSolution.Text = listView.SelectedItems[0].Text;
                    lblSelectedSourceSolution.ForeColor = Color.Green;
                }
                else if (listView.Name.Equals("lstTargetSolutions"))
                {
                    lblSelectedTargetSolution.Text = listView.SelectedItems[0].Text;
                    lblSelectedTargetSolution.ForeColor = Color.Green;
                }

                if (lstSourceSolutions.SelectedItems.Count == 1
                && lstTargetSolutions.SelectedItems.Count == 1
                && _sourceService != null
                && _targetService != null)
                {
                    tsbCompareSolutions.Enabled = true;
                }
            }
        }

        /// <summary>
        /// When the user clicks on a column of a solution list, reorder the list.
        /// </summary>
        private void lstSolutions_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            var listView = (ListView)sender;
            if (listView == null)
            {
                throw new ApplicationException("An error occured: object sender should not be null at this point.");
            }

            listView.Sorting = listView.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
            listView.ListViewItemSorter = new ListViewItemComparer(e.Column, listView.Sorting);
        }

        /// <summary>
        /// When the user close the plugin tab, delete temporary files.
        /// </summary>
        private void TsbCloseClick(object sender, EventArgs e)
        {
            if (OnCloseTool != null)
            {
                OnCloseTool(this, null);
            }
        }

        #endregion Methods
    }
}